var Zf2 = {
    /**
     * Coisas iniciais
     *
     * @returns {undefined}
     */
    "init": function () {
        Core.console.debug(this.toString(), 'init', Core.console.type.WARN);
        //delegando a todos os .close-modal para fechar o pai .box-modal
        $('body').delegate('.box-modal .close-modal', 'click', function () {
            $(this).parents('.box-modal').remove();
        });
        Zf2.form.setupInputs();
    },
    /**
     * @returns {String}
     */
    "toString": function () {
        return "Zf2 library";
    },

    /**
     * Controle de foco quando tem modal
     * 
     * @param {jQuery object} modal
     * @returns {start:function(){},stop:function(){}}
     */
    "focusControlOnModal": function (modal) {
        var _interval = 0;
        var _timeout = 500;
        return {
            "start": function () {
                if (_interval === 0) {
                    _interval = setInterval(function () {
//                    Core.console.debug('SICADE.focusControlOnModal called');
                        if (modal.length > 0) {
//                        Core.console.debug('procurar elemento com foco...');
                            $(":focus").each(function () {
//                            Core.console.debug('existe elemento com foco...', $(this));
                                var focused = $(this);
                                if (modal.find(focused).length === 0) {
//                                Core.console.debug('não é filho do modal, tira o foco!');
//                                    modal.find('a,button,:input').focus();
                                    focused.blur();
                                } else {
//                                Core.console.debug('é filho do modal, deixa queto!');
                                }
                            });
                        }
//                    Core.console.debug('SICADE.focusControlOnModal done');
                    }, _timeout);
                }
                Core.console.debug([modal, _interval], 'Zf2.focusControlOnModal.start', Core.console.type.INFO);
            },
            "stop": function () {
                Core.console.debug([modal, _interval], 'Zf2.focusControlOnModal.stop', Core.console.type.WARN);
                clearInterval(_interval);
            }
        };
    },
    /**
     * Texto do carregando
     * 
     * @type {String}
     */
    "_loadingText": '<center><img src="/img/ajax-loader.gif" /></center>',
    /**
     * Contador de diálogos de carregando
     *
     * @type {Number}
     */
    "_loadingCounter": 0,
    /**
     * Controlador de diálogo de carregando
     *
     * @returns {Zf2.loading()}
     */
    "loading": function ()
    {
        var id = sprintf('loading-%d', ++Zf2._loadingCounter);
        //body append

        var html = '<div class="modal hide fade" id="' + id + '">';
        html += '       <div class="modal-header">';
        html += '           <h3>Carregando</h3>';
        html += '       </div>';
        html += '           <div class="modal-body">';
        html += '       ' + Zf2._loadingText;
        html += '           </div>';
        html += '   </div>';
        $('body').append(html);
        var loading = $('#' + id);

        return {
            "close": function ()
            {
                loading.modal('hide');
            },
            "show": function ()
            {
                loading.modal('show');
            }
        };
    },
    /**
     * Atalho para a jqGrid
     *
     * @param {object} options
     *    id               | string        | Id da grid
     *    columns          | Array         | Configuração das colunas da jqGrid
     *                     |               |
     *    caption          | string|Array  | Caso passado um Array, cada
     *                     |               | item do Array deve uma string
     *                     |               | com o html de cada elemento
     *                     |               | que vai para o titulo da grid.
     *                     |               | Lembrando que se passado um
     *                     |               | elemento html esse mesmo tem
     *                     |               | que conter a classe 'gridTitleItem'
     *                     |               | para ele ser apresentado da correta forma.
     *                     |               |
     *    datatype         | string        | Tipo de dados da grid pode ser 'local' ou 'json'
     *                     |               |
     *    sortname         | string        | Nome da coluna que vai ser sorteada por padrão
     *                     |               |
     *    url              | object        | Obrigatório quando o data type for 'json'.
     *                     |               | Objeto com 'module', 'controller' ou 'action' se não
     *                     |               | passar nada vai chamar a action 'grid' da mesma
     *                     |               | controller e do mesmo module
     *                     |               |
     *    postData         | mixed         | Os dados que serão postados
     *                     |               |
     *    postElement      | object jQuery | Elemento que será postado sempre
     *                     |               |
     *    width            | int           | Largura da grid
     *                     |               |
     *    height           | int           | Altura da grid
     *                     |               |
     *    rowNum           | int           | Quantidade de linhas padrao para exibição
     *                     |               |
     *    mutiselect       | boolean       | Se os registros da grid são multi-selecionaveis
     *                     |               |
     *    actions          | object        | Cria um ou mais botões para cada linha da grid
     *                     |               | sendo que pode-se passar um objeto com 'edit',
     *                     |               | 'view' ou 'delete' (outros viram depois) e o
     *                     |               | nome da sua função. Essa função será chamada
     *                     |               | passando como paramêtro o id da linha clicada.
     *                     |               |
     *    extraActions     | object        | Cria uma ou mais colunas com uma imagem e ação
     *                     |               | no clique dela. Tem que passar os parametros
     *                     |               | conforme o exemplo.
     *                     |               |
     *    hasFilterToolbar | boolean       | Se existirá a barra de filtro
     *                     |               |
     *    hasNavigator     | boolean       | Se existirá busca avançada e o refresh grid
     *                     |               |
     *    hasPagination    | boolean       | Se existirá a paginação
     *                     |               |
     *    onSelectRow      | function      | callback de quando seleciona uma linha
     *                     |               |
     *    onBeforeLoad     | function      | callback antes de carregar
     *                     |               |
     *    onLoad           | function      | callback depois de carregar
     *
     * @returns {Zf2.Grid}
     */
    "Grid": function (options)
    {
        var _self = this;
//        var _editMode = false;
        var _postElement = $();
        options = options || {};
        try {

            if (typeof (options) !== "object") {
                throw new Core.Exception("Zf2.Grid: Passe as opções corretamente");
            }

            if (!isset(options.id)) {
                throw new Core.Exception("Zf2.Grid: Passe o ID da grid");
            }

            if (!isset(options.columns)) {
                throw new Core.Exception("Zf2.Grid: Passe a configuração das colunas da grid");
            }

            var id = options.id;
            var gridElement = $("#" + id);
            /**
             * Método que acrescenta dados na url da grid
             *
             * @return {Zf2.Grid} | object
             */
            this.setPostData = function (data, internalPropose)
            {
                return gridElement.setPostData(data, internalPropose);
            };
            gridElement.setPostData = function (data, internalPropose)
            {
                try {
                    internalPropose = internalPropose || false;
                    if (gridElement.length === 0) {
                        throw new Core.Exception("Zf2.Grid.reload(): Objeto da grid não existe");
                    }
                    data = data || {};
                    if (typeof (data) === "string") {
                        data = $(data);
                    }
                    if (isset(data.jquery)) {
                        if (!data.is(':input')) {
                            data = data.find(':input').not(':disabled,:button');
                        }
                        data.each(function () {
                            if ($(this).is('.flop')) {
                                $(this).find('option').attr('selected', true);
                            }
                            if ($(this).is('.flip')) {
                                $(this).find('option').removeAttr('selected');
                            }
                        });
                        data = Core.parseJSON(data);
                        ;
                    }
                    data = $.extend(Core.parseJSON(_postElement), data);
                    if (typeof (data) !== "object") {
                        throw new Core.Exception("Zf2.Grid.setDataPost: Parametro 'data' dever ser um objeto");
                    }
                    if (false === internalPropose) {
                        gridElement.setGridParam({"postData": data});
                        return this;
                    }
                } catch (e) {
                    Core.exceptionHandler(e);
                }
                return data;
            };
            if (gridElement.length === 0) {
                throw new Core.Exception("Zf2.Grid: Objeto da grid não existe");
            }

            var columns = options.columns;
            var width = isset(options.width) ? options.width : 'auto';
            var height = isset(options.height) ? options.height : "auto";
            var rowNum = isset(options.rowNum) ? options.rowNum : 5;
            var mutiselect = isset(options.mutiselect) ? options.mutiselect : false;
            var sortname = isset(options.sortname) ? options.sortname : "";
            var sortorder = isset(options.sortorder) ? options.sortorder : "asc";
            var actions = isset(options.actions) ? options.actions : {};
            var extraActions = isset(options.extraActions) ? options.extraActions : [];
            var datatype = isset(options.datatype) ? options.datatype : "json";
            var hasFilterToolbar = isset(options.hasFilterToolbar) ? options.hasFilterToolbar : true;
            var hasNavigator = isset(options.hasNavigator) ? options.hasNavigator : true;
            var data = isset(options.postData) ? options.postData : {};
            var pagerId = (isset(options.hasPagination) ? options.hasPagination : true) ? "#" + id + "_pager" : '';
            _postElement = isset(options.postElement) ? options.postElement : _postElement;
            if (!_postElement.jquery) {
                throw new Core.Exception("Zf2.Grid: parametro 'postElement' tem que ser um objeto jQuery válido");
            }

            if (pagerId !== '') {
                var pager = $(pagerId);
                if (pager.length === 0) {
                    throw new Core.Exception("Zf2.Grid: Objeto do paginador não existe");
                }
            } else {
                hasNavigator = false;
            }

            var url = null;
            var request = new Array();
            if (datatype === 'json') {
                request[0] = baseUrl;
                request[1] = (isset(options.url) && isset(options.url.module)) ? options.url.module : baseRequest.module;
                request[2] = (isset(options.url) && isset(options.url.controller)) ? options.url.controller : baseRequest.controller;
                request[3] = (isset(options.url) && isset(options.url.action)) ? options.url.action : "grid";
                url = request.join('/');
            }

            var caption = isset(options.caption) ? options.caption : "";
            if (caption instanceof Array) {
                caption = caption.join(" ");
            }

            //extra actions
            var extraActionsCount = count(extraActions);
            if (extraActionsCount > 0) {
                for (var extraActionIndex in extraActions) {
                    var extraAction = extraActions[extraActionIndex];
                    var exraActionColumnOptions = {
                        "name": "extraAction_" + extraActionIndex,
                        "label": extraAction.label,
                        "align": "center",
                        "sortable": false,
                        "search": false,
                        "fixed": true
                    };
                    if ("width" in extraAction) {
                        exraActionColumnOptions = $.extend(exraActionColumnOptions, {"width": extraAction.width});
                    }

                    columns.push(exraActionColumnOptions);
                }
            }

            //actions
            var actionsCount = count(actions);
            if (actionsCount > 0) {
                columns.push({
                    "name": "actions",
                    "label": " ",
                    "width": 50 * actionsCount,
                    "align": "center",
                    "sortable": false,
                    "search": false,
                    "fixed": true
                });
            }

            var _createGridButtons = function (rowId, actions, grid) {
                try {
                    var classButton = "";
                    var titleButton = "";
                    var buttons = "";
                    var types = [
                        "download",
                        "edit",
                        "delete",
                        "view",
                        "add",
                        "note",
                        "print",
                        "check",
                        "chart",
                        "cancel"
                    ];
                    for (var action in actions) {
                        if (in_array(action, types)) {
                            var funcAction = actions[action];
                            switch (action) {
                                case types[0]://"download":
                                    classButton = "gridDownloadButton";
                                    titleButton = "Baixar";
                                    break;
                                case types[1]://"edit":
                                    classButton = "gridEditButton";
                                    titleButton = "Editar Registro";
                                    break;
                                case types[2]://"delete":
                                    classButton = "gridDeleteButton";
                                    titleButton = "Excluir Registro";
                                    break;
                                case types[3]://"view":
                                    classButton = "gridViewButton";
                                    titleButton = "Detalhar Registro";
                                    break;
                                case types[4]://"add":
                                    classButton = "gridAddButton";
                                    titleButton = "Adicionar Registro";
                                    break;
                                case types[5]://"note":
                                    classButton = "gridNoteButton";
                                    titleButton = "Avaliar Registro";
                                    break;
                                case types[6]://"print":
                                    classButton = "gridPrintButton";
                                    titleButton = "Imprimir";
                                    break;
                                case types[7]://"check":
                                    classButton = "gridCheckButton";
                                    titleButton = "Validar Registro";
                                    break;
                                case types[8]://"chart":
                                    classButton = "gridChartButton";
                                    titleButton = "Gráfico";
                                    break;
                                case types[9]://"cancel":
                                    classButton = "gridCancelButton";
                                    titleButton = "Cancelar";
                                    break;
                                default:
                                    throw new Core.Exception("Zf2.Grid: Ação '" + action + "' não existe");
                                    break;
                            }

                            titleButton = ("title" in actions) ? actions.title : titleButton;
                            //@TODO: ver uma forma de testar se uma função (em string) existe...
//                            Core.console.warn(function_exists( funcAction ),funcAction );
//                            if (!function_exists( funcAction )) {
//                                    throw new Core.Exception( "Zf2.Grid: Funcão '"+ funcAction +"', da ação '"+ action +"', não existe" );
//                                }

                            var gridId = '#' + gridElement.attr('id');
                            var buttonId = ("id" in actions) ? 'id="' + gridElement.attr('id') + "-" + rowId + actions.id + '"' : "";
                            buttons += '<button type="button" class="gridButton ' + classButton + '" title="' + titleButton + '" onclick="' + funcAction + '( \'' + rowId + '\', \'' + gridId + '\' )" ' + buttonId + '></button>';
                        }
                    }
                } catch (e) {
                    Core.exceptionHandler(e);
                    buttons = "";
                }
                return buttons;
            };
            if (isset(options.onSelectRow)) {
                gridElement.addClass('rowClicable');
            }

            var gridInitOptions = {
                "url": url,
                "postData": this.setPostData(data, true),
                "loadui": "block",
                "datatype": datatype,
                "colModel": columns,
                "width": width,
                "height": height,
                "altRows": true,
                "rowNum": rowNum,
                "rowList": [5, 10, 50, 100, 500, 1000],
                "pager": pagerId,
                "sortname": sortname,
                "sortorder": sortorder,
                "viewrecords": true,
                "caption": caption,
                "multiselect": mutiselect,
                "onSelectRow": function (rowid, status, e) {
                    e = e || {"type": "fail"};
                    if (status) {
                        if (e.type === 'click') {
                            Core.callbackHandler(options.onSelectRow, rowid);
                        } else {
                            gridElement.resetSelection();
                        }
                    }
                },
                "mtype": "POST",
                "loadBeforeSend": function () {
                    Core.callbackHandler(options.onBeforeLoad, _self);
//                    if (_editMode === true) {
//                        gridElement.find('.editable').remove();
//                    }
                },
//                "beforeRequest" : function() {
//                },
                "beforeProcessing": function (response) {
                    if (typeof (response) === "object") {
                        Zf2.Ajax().responseHandle(response);
                    }
                },
                "loadError": function (XMLHttpRequest, textStatus, errorThrown) {
                    Zf2.Ajax().errorHandle(XMLHttpRequest, textStatus, errorThrown);
                },
                "loadComplete": function () {
                    Core.callbackHandler(options.onLoad, _self);
                }
            };
            if (actionsCount > 0 || extraActionsCount > 0) {
                gridInitOptions = $.extend({
                    "gridComplete": function () {
                        var grid = $(this);
                        var rowsIds = grid.jqGrid('getDataIDs');
                        for (var i = 0; i < rowsIds.length; i++) {
                            var rowId = rowsIds[i];
                            if (extraActionsCount > 0) {
                                //extra actions
                                for (var extraActionIndex in extraActions) {
                                    var rowData = {};
                                    rowData[ "extraAction_" + extraActionIndex ] =
                                            _createGridButtons(rowId, extraActions[extraActionIndex], grid);
                                    grid.jqGrid('setRowData', rowId, rowData);
                                }
                            }

                            if (actionsCount > 0) {
                                //actions
                                grid.jqGrid('setRowData', rowId, {
                                    "actions": _createGridButtons(rowId, actions)
                                });
                            }
                        }
                    }
                }, gridInitOptions);
            }

            gridElement.jqGrid(gridInitOptions);
            if (true === hasNavigator) {
                gridElement.navGrid(pagerId, {
                    "edit": false,
                    "add": false,
                    "del": false,
                    "search": false
                });
            }
            if (true === hasFilterToolbar) {
                gridElement.filterToolbar({
                    "stringResult": true,
                    "searchOnEnter": false,
                    "defaultSearch": "cn",
                    "beforeSearch": function () {
                        gridElement.setPostData();
                    },
                    "beforeClear": function () {
                        gridElement.setPostData();
                    }
                });
            }


        } catch (e) {
            Core.exceptionHandler(e);
        }

//        var _editModeDecoration = function() {
////            Core.console.warn("Zf2.Grid._editModeDecoration() called");
//            //repintando o select para o padrão do Arena
//            gridElement.find("select.editable").comboboxRepaint();
//
//            gridElement.find(".editable").one('change', function() {
//
////                Core.console.warn("Zf2.Grid._editModeDecoration() gridElement.find('.editable').one('change') called");
//
//                var selectId = $(this).attr('id');
//                var selectIdSplitted = selectId.split('_');
//                var id = selectIdSplitted[0];
//
////                Core.console.warn("Zf2.Grid._editModeDecoration() gridElement.find('.editable').one('change') saveRow(" + id + ")");
//                gridElement.saveRow(id, false, 'clientArray');
////                Core.console.warn("Zf2.Grid._editModeDecoration() gridElement.find('.editable').one('change') editRow(" + id + ")");
//                gridElement.editRow(id);
//
//                _editModeDecoration();
//
////                Core.console.warn("Zf2.Grid._editModeDecoration() gridElement.find('.editable').one('change') done");
//            });
////            Core.console.warn("Zf2.Grid._editModeDecoration() done");
//        };

        /**
         * Método que recarrega a grid mantendo os filtros e a página
         *
         * @return {Zf2.Grid}
         */
        this.reload = function ()
        {
            try {
                if (gridElement.length === 0) {
                    throw new Core.Exception("Zf2.Grid.reload(): Objeto da grid não existe");
                }
                this.setPostData();
                gridElement.trigger("reloadGrid");
            } catch (e) {
                Core.exceptionHandler(e);
            }
            return this;
        };
        /**
         * Método que recarrega a grid reiniciando os filtros e a página
         *
         * @return {Zf2.Grid}
         */
        this.reset = function ()
        {
            try {
                if (gridElement.length === 0) {
                    throw new Core.Exception("Zf2.Grid.reset(): Objeto da grid não existe");
                }
                var refreshButton = $("#refresh_" + id);
                if (hasNavigator === false) {
                    throw new Core.Exception("Zf2.Grid.reset(): Grid sem navigator. Passe a opção 'hasNavigator' como true:boolean");
                }
                this.setPostData();
                refreshButton.click();
            } catch (e) {
                Core.exceptionHandler(e);
            }
            return this;
        };
        /**
         * Retorna uma lista de objetos com os registros da grid se não passar o rowid
         * ou um único objeto passando o rowId
         *
         * @param rowId mixed id da grid
         * @return Array|object
         */
        this.getData = function (rowId)
        {
            try {
                if (gridElement.length === 0) {
                    throw new Core.Exception("Zf2.Grid.getData(): Objeto da grid não existe");
                }

//                if (_editMode === false) {
                return gridElement.getRowData(rowId);
//                } else {
//                    var rowData = {};
//                    if (rowId) {
//                        gridElement.restoreRow(rowId);
//                        rowData = gridElement.getRowData(rowId);
//                        gridElement.editRow(rowId);
//                    } else {
//                        gridElement.getDataIDs().forEach(function(id) {
//                            gridElement.restoreRow(id);
//                        });
//                        rowData = gridElement.getRowData();
//                        gridElement.getDataIDs().forEach(function(id) {
//                            gridElement.editRow(id);
//                        });
//                    }
//                    _editModeDecoration();
//                    return rowData;
//                }


            } catch (e) {
                Core.exceptionHandler(e);
            }

            return {};
        };
        /**
         * Altera o registro da grid e retorna um objeto com os registros da linha da grid
         *
         * @param rowId mixed id da grid
         * @param row object novo registro da grid
         * @return object
         */
        this.setData = function (rowId, row)
        {
            try {
                if (gridElement.length === 0) {
                    throw new Core.Exception("Zf2.Grid.getData(): Objeto da grid não existe");
                }

                gridElement.setRowData(rowId, row);
                return gridElement.getRowData(rowId);
            } catch (e) {
                Core.exceptionHandler(e);
            }

            return {};
        };
        /**
         * Adiciona linha de registro na grid a partir de um
         *
         * @param rowId mixed id da grid
         * @param data json
         * @param position string 'first' or 'last'
         * @param srcrowid integer
         * @return boolean
         */
        this.addDataRow = function (rowId, data, position, srcrowid)
        {
            try {
                if (gridElement.length === 0) {
                    throw new Core.Exception(
                            "Zf2.Grid.addDataRow(): Objeto da grid não existe");
                }

                return gridElement.addRowData(rowId, data, position, srcrowid);
            } catch (e) {
                Core.exceptionHandler(e);
            }

            return false;
        };
        /**
         * Remove linha de registro da grid
         *
         * @param rowId mixed id line
         * @return boolean
         */
        this.delRow = function (rowId)
        {
            try {
                if (gridElement.length === 0) {
                    throw new Core.Exception(
                            "Zf2.Grid.delRow(): Objeto da grid não existe");
                }

                return gridElement.delRowData(rowId);
            } catch (e) {
                Core.exceptionHandler(e);
            }

            return false;
        };
        /**
         * Clears the currently loaded data from grid. If the clearfooter
         * parameter is set to true, the method clears the data placed on
         * the footer row.
         *
         * @param clearfooter boolean
         * @return jQuery gridElement
         */
        this.clearDataGrid = function (clearfooter)
        {
            try {
                if (gridElement.length === 0) {
                    throw new Core.Exception(
                            "Zf2.Grid.clearDataGrid(): Objeto da grid não existe");
                }

                gridElement.clearGridData(clearfooter);
            } catch (e) {
                Core.exceptionHandler(e);
            }
            return gridElement;
        };
        /**
         * Resets (unselects) the selected row(s). Also works in multiselect mode.
         *
         * @return jQuery gridElement
         */
        this.resetSelection = function ()
        {
            try {
                if (gridElement.length === 0) {
                    throw new Core.Exception(
                            "Zf2.Grid.cancelRows(): Objeto da grid não existe");
                }
                gridElement.resetSelection();
            } catch (e) {
                Core.exceptionHandler(e);
            }
            return gridElement;
        };
        /**
         * Retorna true se a grid estiver visível
         *
         * @return boolean
         */
        this.isVisible = function ()
        {
            try {
                if (gridElement.length === 0) {
                    throw new Core.Exception("Zf2.Grid.getData(): Objeto da grid não existe");
                }

                return gridElement.is(":visible");
            } catch (e) {
                Core.exceptionHandler(e);
            }

            return false;
        };
        return this;
    }
};
$(function () {
    Zf2.init();
});